﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Interfaces;
using Microsoft.WindowsMobile.Status;

namespace Cell
{
    public class Cell : ICellOriginator
    {
        ctlMain mainInterface = new ctlMain();
        
        public System.Windows.Forms.UserControl MainInterface
        {
            get { return mainInterface; }
        }

        public string Name
        {
            get { return "Cell"; }
        }

        CustomControls.AlphaImage IModule.IconEnabled
        {
            get { return CustomControls.AlphaImage.CreateFromResource("Cell.Resources.status-cell-active.png"); }
        }

        CustomControls.AlphaImage IModule.IconDisabled
        {
            get { return CustomControls.AlphaImage.CreateFromResource("Cell.Resources.status-cell-inactive.png"); }
        }

        public bool Sleep()
        {
            throw new NotImplementedException();
        }

        public bool Wake()
        {
            throw new NotImplementedException();
        }

        private IPositionHandler host;
        public delegate void RILRESULTCALLBACK(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam);
        public delegate void RILNOTIFYCALLBACK(uint dwCode, IntPtr lpData, uint cbData, uint dwParam);
        public static IntPtr hRil;
        [StructLayout(LayoutKind.Explicit)]
        class RILCELLTOWERINFO
        {
            [FieldOffset(0)]
            uint dwSize;
            [FieldOffset(4)]
            uint dwParams;
            [FieldOffset(8)]
            public uint dwMobileCountryCode;
            [FieldOffset(12)]
            public uint dwMobileNetworkCode;
            [FieldOffset(16)]
            public uint dwLocationAreaCode;
            [FieldOffset(20)]
            public uint dwCellID;
            [FieldOffset(24)]
            uint dwBaseStationID;
            [FieldOffset(28)]
            uint dwBroadcastControlChannel;
            [FieldOffset(32)]
            uint dwRxLevel;
            [FieldOffset(36)]
            uint dwRxLevelFull;
            [FieldOffset(40)]
            uint dwRxLevelSub;
            [FieldOffset(44)]
            uint dwRxQuality;
            [FieldOffset(48)]
            uint dwRxQualityFull;
            [FieldOffset(52)]
            uint dwRxQualitySub;

        }

        [DllImport("ril.dll")]
        private static extern IntPtr RIL_Initialize(uint dwIndex, RILRESULTCALLBACK pfnResult, RILNOTIFYCALLBACK pfnNotify, uint dwNotificationClasses, uint dwParam, out IntPtr lphRil);
        [DllImport("ril.dll", EntryPoint = "RIL_GetCellTowerInfo")]
        private static extern IntPtr RIL_GetCellTowerInfo(IntPtr hRil);
       // [DllImport("ril.dll", EntryPoint = "RIL_Hangup")]
       // private static extern IntPtr RIL_Hangup(IntPtr hRil);
        [DllImport("ril.dll")]
        private static extern IntPtr RIL_Deinitialize(IntPtr hRil);

   
        private static RILCELLTOWERINFO _towerDetails;
        private static AutoResetEvent waithandle = new AutoResetEvent(false);
        private System.Windows.Forms.Timer Celltimer = new System.Windows.Forms.Timer();
        private CellData _currentTower = new CellData();
        private CellData tempTower = new CellData();
        private bool DataValid = false;
        private System.Windows.Forms.Timer DataRequestTimer;
        private System.Windows.Forms.Timer DataValidTimer;
        private System.Windows.Forms.Timer OnOffTimer = new System.Windows.Forms.Timer();
        private int bestSignal =0;
        public int Rate
        {
            get
            {
                return Celltimer.Interval;
            }
            set
            {
                Celltimer.Interval = value;
            }
        }
        public int DataRequestInterval
        {
            get
            {
                return DataRequestTimer.Interval;
            }
            set
            {
                DataRequestTimer.Interval = value;
            }
        }
        public int DataValidInterval
        {
            get
            {
                return DataValidTimer.Interval;
            }
            set
            {
                DataValidTimer.Interval = value;
            }
        }
        

        public Cell()
        {
            Celltimer.Interval = 5000; // 5 seconds
            Celltimer.Tick += new EventHandler(_timer_Tick);
            DataRequestTimer = new System.Windows.Forms.Timer();
            DataValidTimer = new System.Windows.Forms.Timer();
            DataRequestInterval = 20000;
            DataRequestTimer.Tick += new EventHandler(DataRequestTimer_Tick);
            DataValidInterval = 20000;
            DataValidTimer.Tick += new EventHandler(DataValidTimer_Tick);
            OnOffTimer.Tick += new EventHandler(OnOffTimer_Tick);
            _currentTower = null;
            tempTower = null;
        }

        void OnOffTimer_Tick(object sender, EventArgs e)
        {
            OnOffTimer.Enabled = false;
            if (Celltimer.Enabled)
                SetRadioOff();
            else
                SetRadioOn();
        }
        void DataRequestTimer_Tick(object sender, EventArgs e)
        {
            DataRequestTimer.Enabled = false;
            OnRequestedDataAvailable(new PositionEventArgs(null));
            //RequestedDataAvailable(this, EventArgs.Empty, null);

        }
        void DataValidTimer_Tick(object sender, EventArgs e)//ha ez beüt, akkor ezalatt az idő alatt nem jött új adat és így a bent lévő adat már nem érvényes
        {
            DataValidTimer.Enabled = false;

            UpdateDataValid(DataValidTimer.Enabled);

        }
        /// <summary>
        /// Jelenleg időfüggés alapján érvényes az adat, de később bővíthető ebben a függvényben
        /// </summary>
        /// <param name="valid"></param>
        private void UpdateDataValid(bool valid)
        {
            DataValid = valid;
        }
        private void _timer_Tick(object sender, EventArgs e)
        {
          
           
            _currentTower = GetCellTowerInfo(); //lekérdezzük a cellainformációt

            if (_currentTower != null)
            {
                IPositionData[] pos = new IPositionData[1];
                pos[0] = _currentTower;
                if (tempTower == null)
                {
                    OnNewSignal(new PositionEventArgs(pos));
                    bestSignal = _currentTower.SignalStrength;
                }
                else
                {
                    try
                    {
                        if (tempTower.Id != _currentTower.Id) //itt derül ki új cellában vagyunk-e 
                        {
                            bestSignal = _currentTower.SignalStrength;
                            OnNewSignal(new PositionEventArgs(pos));// ha igen akkor NEwsignal eventet váltunk ki
                        }
                        else
                            if (_currentTower.SignalStrength > bestSignal)
                                OnBestSignal(new PositionEventArgs(pos));
                    }
                    catch (Exception ex)
                    {
                        host.WriteDebugLog("Ezt ki kell javítani: " + ex.Message);
                        // de azért én most elsütöm az eventet, mert végülis új cella a kezdőcella is, nekem meg kell :)
                        OnNewSignal(new PositionEventArgs(pos));
                    }
                }
                if (DataRequestTimer.Enabled)//ha kértek adatot akkor visszaküldjuk a frissen beérkező adatot
                {
                    DataRequestTimer.Enabled = false;

                    OnRequestedDataAvailable(new PositionEventArgs(pos));
                    //RequestedDataAvailable(this, EventArgs.Empty, pos);

                }
                if (DataValidTimer.Enabled)                 //ez azért kell, mert a timer úgy indul újra  0tól ha előtte le volt tiltva és Az Enabledet True-ra állítjuk
                    DataValidTimer.Enabled = false;
                DataValidTimer.Enabled = true;
                UpdateDataValid(DataValidTimer.Enabled);//Az adat érvényességét állítjuk be
               
                    

            }
            tempTower = _currentTower;  //eltároljuk az előző cellainformációt
        }


        public static CellData GetCellTowerInfo()
        {
            IntPtr radioInterfaceLayerHandle = IntPtr.Zero;
            IntPtr radioResponseHandle = IntPtr.Zero;

           
            radioResponseHandle = RIL_Initialize(1, new RILRESULTCALLBACK(CellDataCallback), null, 0, 0, out radioInterfaceLayerHandle);

            
            if (radioResponseHandle != IntPtr.Zero)
            {
                return null;
            }

           
            radioResponseHandle = RIL_GetCellTowerInfo(radioInterfaceLayerHandle);

          
            waithandle.WaitOne();

           
            RIL_Deinitialize(radioInterfaceLayerHandle);

           SystemState sig = new SystemState(SystemProperty.PhoneSignalStrength);

            return new CellData()
            {
                Id = Convert.ToInt32(_towerDetails.dwCellID),
                Lac = Convert.ToInt32(_towerDetails.dwLocationAreaCode),
                Mcc = Convert.ToInt32(_towerDetails.dwMobileCountryCode),
                Mnc = Convert.ToInt32(_towerDetails.dwMobileNetworkCode),
                SignalStrength = Convert.ToInt32(sig.CurrentValue),
                
               

            };
        }
        public static void CellDataCallback(uint dwCode, IntPtr hrCmdID, IntPtr lpData, uint cbData, uint dwParam)
        {
            
            _towerDetails = new RILCELLTOWERINFO();

            
            Marshal.PtrToStructure(lpData, _towerDetails);
      
           
            waithandle.Set();
        }




        #region ICellOriginator Members

        public CellData GetData()
        {
            return _currentTower;
        }

        #endregion 

        #region IProximityOriginator Members

        public List<string> GetCurrentContextHashes()
        {
            List<string> temp = new List<string>();
            if (_currentTower != null)
            {
                temp.Add(_currentTower.HashValue);
            }
            return temp;
        }

        public List<IProximityData> GetCurrentContextMembers()
        {
            throw new NotImplementedException();
        }


        public event NewSignalEventHandler NewSignalEvent;
        public event BestSignalEventHandler BestSignalEvent;

        #endregion

        #region IPositionOriginator Members

        public new PositionOriginator GetType() //TODO: Rename this method so it doesn't hide Object.GetType
        {
            return PositionOriginator.Cell;
        }

       
        public IPositionHandler Host
        {
            get
            {
                return host;
            }
            set
            {
                host = value;
            }
        }

       


        public void Initialize()
        {
            Console.WriteLine("Cell module initialized.");
            //OnNewSignal(EventArgs.Empty);
        }

    

        public bool GetRadioStatus()
        {
            return Celltimer.Enabled;
        }

        public int SetRadioOn()
        {
            try
            {
                Celltimer.Enabled = true;
                OnRadioSwitchedOn(EventArgs.Empty);
            }
            catch
            {
                return 1;
            }
            return 0;
        }

        public int SetRadioOff()
        {
            try
            {
                Celltimer.Enabled = false;
                OnRadioSwitchedOff(EventArgs.Empty);
            }
            catch
            {
                return 1;
            }
            return 0;
        }

        public int SetRadioOn(int interval)
        {
            try
            {
                if (OnOffTimer.Enabled)
                    OnOffTimer.Enabled = false;
                OnOffTimer.Interval = interval * 1000;
                if (!Celltimer.Enabled)
                    SetRadioOn();
                OnOffTimer.Enabled = true;
            }

            catch
            {
                return 1;
            }
            return 0;
        }

        public int SetRadioOff(int interval)
        {
            try
            {
                if (OnOffTimer.Enabled)
                    OnOffTimer.Enabled = false;
                OnOffTimer.Interval = interval * 1000;
                if (Celltimer.Enabled)
                    SetRadioOff();
                OnOffTimer.Enabled = true;
            }

            catch
            {
                return 1;
            }
            return 0;
        }

        public int DataRequest()
        {
            try
            {
                if (DataValid)//Ha érvényes az adat akkor egyből küldjük
                {
                    IPositionData[] pos = new IPositionData[1];
                    pos[0] = GetCellTowerInfo();
                    OnRequestedDataAvailable(new PositionEventArgs(pos));
                    //RequestedDataAvailable(this, EventArgs.Empty, pos);
                }
                else//ha nem akkor indul a timer, ha beüt akkor null-t küldünk vissza
                {
                    // DataRequestTimer = new System.Windows.Forms.Timer();
                    if (DataRequestTimer.Enabled) //ez azért kell, mert a timer úgy indul újra  0tól ha előtte le volt tiltva és Az Enabledet True-ra állítjuk
                        DataRequestTimer.Enabled = false;
                    DataRequestTimer.Enabled = true;


                }
                return 0;
            }
            catch (Exception)
            {

                return 1;
            }
        }


        public void OnNewSignal(PositionEventArgs e)
        {
            

           if (NewSignalEvent != null)
                NewSignalEvent(this, e);
        }

        public void OnBestSignal(PositionEventArgs e)
        {

            if (BestSignalEvent != null)
               BestSignalEvent(this, e);
        }

       


        public void OnRadioSwitchedOff(EventArgs e)
        {
            if (RadioSwitchedOffEvent != null)
                RadioSwitchedOffEvent(this, e);
        }

        public void OnRadioSwitchedOn(EventArgs e)
        {

            if (RadioSwitchedOnEvent != null)
                RadioSwitchedOnEvent(this, e);
        }

        public void OnRequestedDataAvailable(PositionEventArgs e)
        {
            if (RequestedDataAvailable != null)
                RequestedDataAvailable(this, e);
        }

        public event RequestedDataAvailableHandler RequestedDataAvailable;

        public event RadioSwitchedOffEventHandler RadioSwitchedOffEvent;

        public event RadioSwitchedOnEventHandler RadioSwitchedOnEvent;

        #endregion


        #region IDisposable Members

        public void Dispose()
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}
